package com.wgo.bpot.common.transport.servicefacade.hessian;

import java.io.IOException;
import java.util.logging.Logger;

import com.caucho.hessian.io.AbstractDeserializer;
import com.caucho.hessian.io.AbstractHessianInput;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.AbstractSerializer;
import com.caucho.hessian.io.AbstractSerializerFactory;
import com.caucho.hessian.io.Deserializer;
import com.caucho.hessian.io.Serializer;
import com.wgo.bpot.common.transport.util.Assert;
import com.wgo.bpot.domain.common.UserRole;
/**
 * @author petterei
 * @version $Id: EnumSerializerFactory.java,v 1.1 2006-01-23 09:27:22 petterei Exp $
 */
public class EnumSerializerFactory extends AbstractSerializerFactory {
	private static final transient Logger log = Logger.getLogger(EnumSerializerFactory.class.getName());
	@Override
	public Serializer getSerializer(Class cl) {
		if (isEnumType(cl)) {
			return new JavaEnumSerializer();
		}
		return null;
	}
	@Override
	public Deserializer getDeserializer(Class cl) {
		if (isEnumType(cl)) {
			return new JavaEnumDeserializer();
		}
		return null;
	}
    
	private static boolean isEnumType(Class cl) {
		boolean result = cl.isEnum()  || (cl.isAnonymousClass() && cl.getSuperclass().isEnum() ) || cl.getSimpleName().endsWith("Enum");
        if (!result && cl.equals(UserRole.class)) {
            //  This is done to get around a problem with Hessian, where it is unable to detect Enums. 
            //  Even the latest version, which supposedly supports Enums, does not correctly detect enums.
            result = true;
        }
		return result;
	}
}

class JavaEnumDeserializer extends AbstractDeserializer {
	@SuppressWarnings("unchecked")
	@Override
	public Object readMap(AbstractHessianInput in) throws IOException {
		String clazz = null;
		String value = null;
		while (!in.isEnd()) {
			clazz = in.readString();
			value = in.readString();
		}
		in.readMapEnd();
		Assert.assertNotNull(clazz, "Enum deserializer: Expected Enum class name");
		Assert.assertNotNull(value, "Enum deserializer: Expected Enum class value");

		Class enumClazz = null;
		try {
			enumClazz = Class.forName(clazz);
		} catch (ClassNotFoundException e) {
			throw new IOException("Expected Enum class (" + clazz + ") was not found");
		}
		return Enum.valueOf(enumClazz, value);
	}
}
class JavaEnumSerializer extends AbstractSerializer {
	private static final transient Logger log = Logger.getLogger(JavaEnumSerializer.class.getName());
	@Override
	public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
		Class cl = obj.getClass();
		String className = cl.getName();
		while (cl.isAnonymousClass()) {
			cl = cl.getSuperclass();
			className = cl.getName();
		}
		out.writeMapBegin(className);
		out.writeString(className);
		out.writeString(obj.toString());
		out.writeMapEnd();
	}
}